package com.neusoft.neuiotms.dcam.workflow.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import javax.persistence.EntityNotFoundException;
import javax.transaction.Transactional;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.neusoft.bizcore.activiti.dto.ProcessInstanceDTO;
import com.neusoft.bizcore.activiti.model.WorkOrder;
import com.neusoft.bizcore.activiti.repository.WorkOrderRepository;
import com.neusoft.bizcore.activiti.service.ProcessInstanceService;
import com.neusoft.bizcore.activiti.service.WorkOrderService;
import com.neusoft.bizcore.auth.common.bean.UserBean;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;
import com.neusoft.neuiotms.common.constant.AHConstants;
import com.neusoft.neuiotms.dcam.constant.DCAMConsts;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.AssetLifeCycleDTO;
import com.neusoft.neuiotms.dcam.fixed.dto.WarehouseRecordDTO;
import com.neusoft.neuiotms.dcam.fixed.model.Asset;
import com.neusoft.neuiotms.dcam.fixed.model.AssetLifeCycle;
import com.neusoft.neuiotms.dcam.fixed.model.AssetType;
import com.neusoft.neuiotms.dcam.fixed.model.Contract;
import com.neusoft.neuiotms.dcam.fixed.model.ContractItem;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetLifeCycleRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.AssetTypeRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.ContractItemRepository;
import com.neusoft.neuiotms.dcam.fixed.repository.ContractRepository;
import com.neusoft.neuiotms.dcam.fixed.service.AssetLifeCycleService;
import com.neusoft.neuiotms.dcam.fixed.service.AssetService;
import com.neusoft.neuiotms.dcam.fixed.service.StorehouseService;
import com.neusoft.neuiotms.dcam.fixed.service.WarehouseRecordService;
import com.neusoft.neuiotms.dcam.workflow.converter.RukuSLConverter;
import com.neusoft.neuiotms.dcam.workflow.dto.RukuSLDTO;
import com.neusoft.neuiotms.dcam.workflow.model.RukuSL;
import com.neusoft.neuiotms.dcam.workflow.repository.RukuSLRepository;
import com.neusoft.neuiotms.dcam.workflow.service.RukuSLService;

@Service
public class RukuSLServiceImpl implements RukuSLService {

    @Autowired
    private WorkOrderService workOrderService;
    @Autowired
    private WorkOrderRepository workOrderRepository;
    @Autowired
    private ProcessInstanceService processInstanceService;
    @Autowired
    private AssetService assetService;
    @Autowired
    private AssetRepository assetRepository;
    @Autowired
    private ContractRepository contractRepository;
    @Autowired
    private RukuSLConverter rukuSLConverter;
    @Autowired
    private RukuSLRepository rukuSLRepository;
    @Autowired
    private AssetTypeRepository assetTypeRepository;
    @Autowired
    private AssetLifeCycleService assetLifeCycleService;
    @Autowired
    private ContractItemRepository contractItemRepository;
    @Autowired
    private AssetLifeCycleRepository assetLifeCycleRepository;
    @Autowired
    private StorehouseService storehouseService;
    @Autowired
    private WarehouseRecordService warehouseRecordService;

    @Transactional
    @Override
    public RukuSLDTO create(final RukuSLDTO dto, final UserBean user) {

        final String taskId = dto.getTaskId();
        final ProcessInstanceDTO instance =
                this.workOrderService.submit(dto.getTitle(), DCAMConsts.PROCESSS_RUKU_SL_KEY, dto.getWorkOrderNum(),
                        user);
        dto.setTaskId(instance.getTaskId());
        dto.setWorkOrderNum(instance.getWorkorderNum());
        dto.setCreateUser(user.getUsername());
        dto.setCreateUserName(user.getName());

        // 查询当前workOrderNum和TaskId下是否存在记录
        final RukuSL oldModel = this.rukuSLRepository.findByWorkOrderNumAndTaskId(
                dto.getWorkOrderNum(), taskId);
        if (oldModel == null) {
            dto.setId(null);
        }

        RukuSL model = this.rukuSLConverter.toModel(dto);
        model = this.rukuSLRepository.save(model);

        // 完成当前节点
        this.processInstanceService.complete(dto.getWorkOrderNum(), dto.getTaskId(), user);

        return this.rukuSLConverter.toDTO(model);
    }

    @Override
    public RukuSLDTO detail(final String workOrderNum, final String taskId, final UserBean user) {
        RukuSL model = null;
        try {
            if (StringUtils.isNotBlank(workOrderNum) && !"NULL".equals(taskId)) {
                model = this.rukuSLRepository.findByWorkOrderNumAndTaskId(workOrderNum, taskId);
                if (model == null) {
                    // 获取前一节点的TaskID
                    final String lastTaskId = this.processInstanceService.getLastTaskId(taskId, user);
                    if (lastTaskId == null) {
                        return new RukuSLDTO();
                    } else {
                        model = this.rukuSLRepository.findByWorkOrderNumAndTaskId(workOrderNum,
                                lastTaskId);
                    }
                }
            } else if ("NULL".equals(taskId)) {
                model = this.rukuSLRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);
            }
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND,
                    new Object[] {workOrderNum },
                    new Object[] {taskId });
        }
        final RukuSLDTO dto = this.rukuSLConverter.toDTO(model);

        final List<AssetLifeCycle> assetList = this.assetLifeCycleRepository.findByWorkNum(workOrderNum);
        if ((assetList != null) && !assetList.isEmpty()) {
            final List<String> codes = assetList.stream().map(l -> l.getCode()).collect(Collectors.toList());
            final Searchable searchable = new Searchable();
            searchable.put("contractNo", dto.getContractCode());
            searchable.put("codes", codes.toArray(new String[codes.size()]));
            dto.setList(this.assetService.index(searchable));
        }

        return dto;
    }

    private List<AssetDTO> generateAssets(final String workOrderNum) {
        final List<AssetDTO> list = new ArrayList<>();
        final List<AssetLifeCycleDTO> lifeList = new ArrayList<>();
        final List<WarehouseRecordDTO> records = new ArrayList<>();

        final RukuSL main = this.rukuSLRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);
        main.getArrivalCount().forEach(l -> {
            // 修改合同项的到货验收数量
            final ContractItem contractItem = this.contractItemRepository.getOne(l.getItemId());
            contractItem.setAcceptedCount(l.getCount() + contractItem.getAcceptedCount());
            this.contractItemRepository.save(contractItem);

            switch (main.getCategories()) {
            case "3":
                // 判断位置是不是库房
                final Boolean isStore = this.storehouseService.LocationIsStorehouse(main.getLocation());

                final Asset xhAsset = this.assetRepository
                        .findTopBySmallTypeCodeAndSpecificationsAndManagementOrgCodeOrderByCreateTimeDesc(
                                contractItem.getAssetType().getCode(), l.getSpecification(), null);
                // 存在的情况添加数量
                final AssetDTO asset = new AssetDTO();
                if (null != xhAsset) {
                    xhAsset.setAmount(xhAsset.getAmount() + l.getCount());
                    this.assetRepository.save(xhAsset);
                    // 生命周期
                    lifeList.add(AssetLifeCycleDTO.builder().userName(main.getCreateUserName()).code(xhAsset.getCode())
                            .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_DAOHU)
                            .content(xhAsset.getName() + "物资入库,入库数量为" + l.getCount()).workNum(workOrderNum)
                            .build());
                } else {
                    asset.setName(l.getProductName());
                    asset.setPurchaseDate(main.getPurchaseDate());
                    asset.setSpecifications(l.getSpecification());
                    asset.setMoney(l.getAmount());
                    asset.setContractName(main.getContractName());
                    asset.setContractNo(main.getContractCode());
                    asset.setSmallTypeCode(l.getTypeCode());
                    asset.setSmallTypeName(l.getTypeName());
                    asset.setAmount(l.getCount());
                    asset.setBrand(contractItem.getProduct() != null ? contractItem.getProduct().getBrand() : "");
                    asset.setLocation(main.getLocation());
                    asset.setLocationName(main.getLocationName());
                    asset.setCategories("3");
                    asset.setBelongs(AHConstants.BELONG_SL_CODE);
                    asset.setStatus(DCAMConsts.ASSET_STATUS_UNUSED);
                    final AssetType type = this.assetTypeRepository.findByCode(l.getTypeCode());
                    if (type.getParent() != null) {
                        asset.setMiddleTypeCode(type.getParent().getCode());
                        asset.setMiddleTypeName(type.getParent().getName());
                        if (null != type.getParent().getParent()) {
                            asset.setBigTypeCode(type.getParent().getParent().getCode());
                            asset.setBigTypeName(type.getParent().getParent().getName());
                        }
                    }
                    final AssetDTO dto = this.assetService.create(asset, null, null);
                    // 生命周期
                    lifeList.add(AssetLifeCycleDTO.builder().userName(main.getCreateUserName()).code(dto.getCode())
                            .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_DAOHU)
                            .content(dto.getName() + "物资入库,入库数量为" + l.getCount()).workNum(workOrderNum)
                            .build());
                }
                // 库房记录
                if (isStore) {
                    records.add(WarehouseRecordDTO.builder()
                            .name(contractItem.getProduct() != null ? contractItem.getProduct().getName()
                                    : l.getTypeName())
                            .specifications(l.getSpecification())
                            .brand((null != xhAsset) ? xhAsset.getBrand() : asset.getBrand())
                            .smallTypeName(l.getTypeName())
                            .smallTypeCode(l.getTypeCode()).contractNo(main.getContractCode())
                            .contractName(main.getContractName()).amount(l.getCount()).location(main.getLocation())
                            .locationName(main.getLocationName()).type("1").build());
                }
                break;

            default:
                break;
            }

        });

        if (!"3".equals(main.getCategories())) {
            main.getAssetList().forEach(l -> {
                // 修改合同项的到货验收数量
                final ContractItem contractItem = this.contractItemRepository.getOne(l.getItemId());
                final AssetDTO asset = new AssetDTO();
                //                final Manufacturer manufacturer = contractItem.getContract().getManufacturer();
                asset.setName(l.getProductName());
                asset.setPurchaseDate(main.getPurchaseDate());
                asset.setSpecifications(l.getSpecification());
                asset.setMoney(l.getMoney());
                asset.setContractName(main.getContractName());
                asset.setContractNo(main.getContractCode());
                asset.setSmallTypeCode(l.getTypeCode());
                asset.setSmallTypeName(l.getTypeName());
                asset.setBrand(contractItem.getProduct() != null ? contractItem.getProduct().getBrand() : "");
                asset.setLocation(l.getLocation());
                asset.setLocationName(l.getLocationName());
                asset.setMaintenanceStartTime(l.getMaintenanceStartTime());
                asset.setMaintenanceEndTime(l.getMaintenanceEndTime());
                asset.setMeasureUnit(l.getMeasureUnit());
                asset.setUsePeriod(l.getUsePeriod());
                asset.setAmount(1);
                asset.setSerialnumber(l.getSerialnumber());
                asset.setBelongs(AHConstants.BELONG_SL_CODE);
                asset.setStatus(DCAMConsts.ASSET_STATUS_UNUSED);
                asset.setBrand(l.getBrand());
                //                asset.setSupplierId(manufacturer != null ? manufacturer.getId() : null);
                asset.setSupplierName(contractItem.getContract().getManufacturerName());
                final AssetType type = this.assetTypeRepository.findByCode(l.getTypeCode());
                if (type.getParent() != null) {
                    asset.setMiddleTypeCode(type.getParent().getCode());
                    asset.setMiddleTypeName(type.getParent().getName());
                    if (null != type.getParent().getParent()) {
                        asset.setBigTypeCode(type.getParent().getParent().getCode());
                        asset.setBigTypeName(type.getParent().getParent().getName());
                        switch (asset.getBigTypeCode()) {
                        case DCAMConsts.ASSET_SL_DZ_BIG_TYPE_CODE:
                            asset.setCategories("2");
                            break;
                        case DCAMConsts.ASSET_SL_GD_BIG_TYPE_CODE:
                            asset.setCategories("1");
                            break;
                        default:
                            break;
                        }
                    }
                }
                final AssetDTO dto = this.assetService.create(asset, null, null);
                list.add(dto);

                // 生命周期
                lifeList.add(AssetLifeCycleDTO.builder().userName(main.getCreateUserName()).code(dto.getCode())
                        .lifeCycle(DCAMConsts.ASSET_LIFE_TYPE_DAOHU)
                        .content(asset.getName() + "已入库").workNum(workOrderNum).build());
            });
        }

        if (records.size() > 0) {
            this.warehouseRecordService.batchCreate(records);
        }

        if (lifeList.size() > 0) {
            this.assetLifeCycleService.batchCreate(lifeList);
        }

        return list;
    }

    @Override
    public List<RukuSLDTO> search(final Searchable searchable) {
        final List<RukuSL> models = this.rukuSLRepository.search(searchable);
        return this.rukuSLConverter.toListDTO(models);
    }

    @Override
    public Page<RukuSLDTO> search(final Pageable pageable, final Searchable searchable) {

        final Searchable params = new Searchable();
        params.put("type", "RukuSL");
        params.put("status", "finish");
        final List<WorkOrder> finishedWorkorderList = this.workOrderRepository.search(params);
        final List<String> finishedWorkorderWorkNumList =
                finishedWorkorderList.stream().map(it -> it.getWorkOrderNum()).collect(Collectors.toList());

        searchable.put("workOrderNumIn", finishedWorkorderWorkNumList);
        final Page<RukuSL> models = this.rukuSLRepository.search(pageable, searchable);
        final Page<RukuSLDTO> dtos = this.rukuSLConverter.toPageDTO(models);
        return dtos;
    }

    @Override
    public RukuSLDTO detail(final Long id) {
        final RukuSL model = this.rukuSLRepository.findById(id).orElse(null);
        if (null != model) {
            final RukuSLDTO dto = this.rukuSLConverter.toDTO(model);
            final List<AssetLifeCycle> assetList = this.assetLifeCycleRepository.findByWorkNum(model.getWorkOrderNum());
            if ((assetList != null) && !assetList.isEmpty()) {
                final List<String> codes = assetList.stream().map(l -> l.getCode()).collect(Collectors.toList());
                final Searchable searchable = new Searchable();
                searchable.put("contractNo", dto.getContractCode());
                searchable.put("codes", codes.toArray(new String[codes.size()]));
                dto.setList(this.assetService.index(searchable));
            }
            return dto;
        }
        return null;
    }

    @Override
    public void processEnd(final String workOrderNum) {
        final RukuSL model = this.rukuSLRepository.findTopByWorkOrderNumOrderByCreateTimeDesc(workOrderNum);
        // 生成资产信息
        this.generateAssets(workOrderNum);

        // 判断合同是否已经全部到货
        // 更新合同状态为已到货
        final Contract contract = this.contractRepository.findByCode(model.getContractCode());
        final List<ContractItem> filterData =
                contract.getItems().stream()
                        .filter(l -> l.getCount() != l.getAcceptedCount()).collect(Collectors.toList());

        if (filterData.isEmpty()) {
            contract.setWhetherArrival(true);
            this.contractRepository.save(contract);
        }
    }
}
